04. 前向传播
前向传播
MiniFlow
具有以下两个方法,可以帮助你定义和通过图表传播值:topological_sort()
和 forward_pass()
。

An example of topological sorting
为了定义你的网络,你需要定义节点的操作顺序。因为某些节点的输入取决于其他节点的输出,你需要按以下方式扁平化图表:在进行计算之前,每个节点的输入依赖项都已解决,这种技巧叫做拓扑排序。
topological_sort()
函数使用 Kahn 算法进行拓扑排序。该方法的细节方面并不重要,结果很重要;topological_sort()
返回一个排好序的节点列表,所有计算都可以按序进行。topological_sort()
传入 feed_dict
,我们按此方法为 Input
节点设置初始值。feed_dict
由 Python 字典数据结构表示。以下是示例使用情况:
# Define 2 `Input` nodes.
x, y = Input(), Input()
# Define an `Add` node, the two above`Input` nodes being the input.
add = Add(x, y)
# The value of `x` and `y` will be set to 10 and 20 respectively.
feed_dict = {x: 10, y: 20}
# Sort the nodes with topological sort.
sorted_nodes = topological_sort(feed_dict=feed_dict)
(你可以在下面的编程测验中找到 miniflow.py 中 topological_sort()
的源代码。)
你还可以使用方法 forward_pass()
,该方法会实际地运行网络并输出一个值。
def forward_pass(output_node, sorted_nodes):
"""
Performs a forward pass through a list of sorted nodes.
Arguments:
`output_node`: The output node of the graph (no outgoing edges).
`sorted_nodes`: a topologically sorted list of nodes.
Returns the output node's value
"""
for n in sorted_nodes:
n.forward()
return output_node.value
练习 1 - 向前传递值
请创建并运行此图表!

你将在此练习中运行的图表。但是节点值可能会改变!
设置
查看 nn.py
和 miniflow.py
。
nn.py 中已经提供了神经网络架构。你需要完成 MiniFlow
,使其能够运转。
对于此测验,请完成以下步骤:
- 打开下面的
nn.py
。你不需要更改任何内容。我只是希望你能看下MiniFlow
的工作方式。 - 打开
miniflow.py
。完成Add
类中forward
的方法。要通过此测验,只需正确地实现forward
。 - 通过点击“测试运行”测试你的网络。如果输出看起来正常,则点击“提交”。
(你将在下个页面看到解决方案)。
Start Quiz:
"""
This script builds and runs a graph with miniflow.
There is no need to change anything to solve this quiz!
However, feel free to play with the network! Can you also
build a network that solves the equation below?
(x + y) + y
"""
from miniflow import *
x, y = Input(), Input()
f = Add(x, y)
feed_dict = {x: 10, y: 5}
sorted_nodes = topological_sort(feed_dict)
output = forward_pass(f, sorted_nodes)
# NOTE: because topological_sort sets the values for the `Input` nodes we could also access
# the value for x with x.value (same goes for y).
print("{} + {} = {} (according to miniflow)".format(feed_dict[x], feed_dict[y], output))
"""
You need to change the Add() class below.
"""
class Node(object):
def __init__(self, inbound_nodes=[]):
# Nodes from which this Node receives values
self.inbound_nodes = inbound_nodes
# Nodes to which this Node passes values
self.outbound_nodes = []
# A calculated value
self.value = None
# Add this node as an outbound node on its inputs.
for n in self.inbound_nodes:
n.outbound_nodes.append(self)
# These will be implemented in a subclass.
def forward(self):
"""
Forward propagation.
Compute the output value based on `inbound_nodes` and
store the result in self.value.
"""
raise NotImplemented
class Input(Node):
def __init__(self):
# an Input node has no inbound nodes,
# so no need to pass anything to the Node instantiator
Node.__init__(self)
# NOTE: Input node is the only node that may
# receive its value as an argument to forward().
#
# All other node implementations should calculate their
# values from the value of previous nodes, using
# self.inbound_nodes
#
# Example:
# val0 = self.inbound_nodes[0].value
def forward(self, value=None):
if value is not None:
self.value = value
class Add(Node):
def __init__(self, x, y):
# You could access `x` and `y` in forward with
# self.inbound_nodes[0] (`x`) and self.inbound_nodes[1] (`y`)
Node.__init__(self, [x, y])
def forward(self):
"""
Set the value of this node (`self.value`) to the sum of its inbound_nodes.
Remember to grab the value of each inbound_node to sum!
Your code here!
"""
"""
No need to change anything below here!
"""
def topological_sort(feed_dict):
"""
Sort generic nodes in topological order using Kahn's Algorithm.
`feed_dict`: A dictionary where the key is a `Input` node and the value is the respective value feed to that node.
Returns a list of sorted nodes.
"""
input_nodes = [n for n in feed_dict.keys()]
G = {}
nodes = [n for n in input_nodes]
while len(nodes) > 0:
n = nodes.pop(0)
if n not in G:
G[n] = {'in': set(), 'out': set()}
for m in n.outbound_nodes:
if m not in G:
G[m] = {'in': set(), 'out': set()}
G[n]['out'].add(m)
G[m]['in'].add(n)
nodes.append(m)
L = []
S = set(input_nodes)
while len(S) > 0:
n = S.pop()
if isinstance(n, Input):
n.value = feed_dict[n]
L.append(n)
for m in n.outbound_nodes:
G[n]['out'].remove(m)
G[m]['in'].remove(n)
# if no other incoming edges add to S
if len(G[m]['in']) == 0:
S.add(m)
return L
def forward_pass(output_node, sorted_nodes):
"""
Performs a forward pass through a list of sorted nodes.
Arguments:
`output_node`: A node in the graph, should be the output node (have no outgoing edges).
`sorted_nodes`: A topologically sorted list of nodes.
Returns the output Node's value
"""
for n in sorted_nodes:
n.forward()
return output_node.value